package com.eunion.core.common.jpa.query;

import java.util.Optional;
import java.util.function.Consumer;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.util.Assert;

public final class FindByKeyQueryRequirement<Entity, Bean>
        implements QueryRequirement<Entity, Bean>, BasicDelete<Entity> {

    private static final long serialVersionUID = 1L;

    private static final String DEFAULT_KEY_COLUMN = "key";

    private final String key;

    private final String keyColumn;

    private final Optional<Consumer<Root<Entity>>> fectchStrategy;

    public FindByKeyQueryRequirement(String key) {
        this(key, DEFAULT_KEY_COLUMN);
    }

    public FindByKeyQueryRequirement(String key, Consumer<Root<Entity>> fectchStrategy) {
        this(key, DEFAULT_KEY_COLUMN, fectchStrategy);
    }

    public FindByKeyQueryRequirement(String key, String keyColumn) {
        this(key, DEFAULT_KEY_COLUMN, null);
    }

    public FindByKeyQueryRequirement(String key, String keyColumn, Consumer<Root<Entity>> fectchStrategy) {
        Assert.notNull(key, "key must not be null");
        Assert.notNull(keyColumn, "keyColumn must not be null");
        this.key = key;
        this.keyColumn = keyColumn;
        this.fectchStrategy = Optional.ofNullable(fectchStrategy);
    }

    @Override
    public void applyFetches(Root<Entity> root) {
        if (fectchStrategy.isPresent()) {
            fectchStrategy.get().accept(root);
        }
    }

    @Override
    public Predicate where(Root<Entity> root, CriteriaQuery<Bean> query, CriteriaBuilder cb) {
        return cb.equal(root.get(keyColumn), key);
    }

    @Override
    public Predicate where(Root<Entity> root, CriteriaDelete<Entity> delete, CriteriaBuilder cb) {
        return cb.equal(root.get(keyColumn), key);
    }

}
